<?php
/*	Created by Alexander Alexandrov aka SS
			hazg@mail.ru				*/
define('SSLIB_Form', TRUE);
if(!defined("SSLIB_Html")) die("Html class missing");

ssinc('post');
class Form
{
	public static $toolJs = '
	var sslib_checkboxes=new Array();
	var sslib_hiddens=new Array();
	var sslib_nullHidden=document.createElement(\'input\');
	sslib_nullHidden.setAttribute(\'type\',\'hidden\');
	sslib_nullHidden.setAttribute(\'value\',\'0\');
	function sslib_checkboxhack(el)
	{
		sslib_checkboxes.push(el);
		var tempHidden=sslib_nullHidden.cloneNode(true);
		tempHidden.setAttribute(\'name\',el.getAttribute(\'name\'));
		sslib_hiddens.push(tempHidden);
	}
	function sslib_hackhiddens()
	{
		for(i=0;i!=sslib_checkboxes.length;i++)
			sslib_checkboxes[i].parentNode.insertBefore(sslib_hiddens[i],sslib_checkboxes[i])
	}
	function sslib_fullform(keys,vals,form)
	{
		var f=document.getElementById(form);
		for(var i=0;i!=keys.length;i++)
		{
			var el=f.elements.namedItem(keys[i]);
			if(!el)continue;
			var v=vals[i];
			switch(el.type)
			{
				case"text":
					el.value=v;break;
				case"textarea":
					var hasInnerText=(document.getElementsByTagName("body")[0].innerText!=undefined)?true:false;
					if(!hasInnerText)
					{
						el.textContent=v;
					}
					else
					{
						el.innerText=v;
					}
				break;
				case"checkbox":
					sslib_checkboxhack(el);
					el.checked=(v!=0)?true:false;
				break;
				case"radio":
					el.checked=(el.value==v)?true:false;
				break;
				case"hidden":
					el.value=v;
				break;
				default:
				if(((el.tagName+\'\').indexOf("SELECT")==0))
				{
					for(var si=0;si!=el.options.length;si++)
						if(el.options[si].value==v)
							el.selectedIndex=si;
				}
				break;
			}
		}
		sslib_hackhiddens();
	}';
	private $table;
	private $form;
	private $key;
	private static $key_lenght = 32;
	private $formid = '';
	private $fieldid = null;
	private $hidden_values = null;
	private $post;
	private $id = null;
	function Form($table, $form, $fieldid = null, $key = 'id', $hidden_values = null)
	{

		if(!Page::Get('sslib_form_js'))
			Page::JavaScript(Form::$toolJs);

		Page::Set('sslib_form_js',true);
		
	    $this->hidden_values = $hidden_values;
	    $this->key = $key;
		$this->table = $table;
		$this->form = $form;
		$this->fieldid = $fieldid;
		
		$this->id = $this->getFieldId();
		
		$this->post = Post::GetArray();
		if(Post::String('sslib_form_key') /*&& Post::String('sslib_form_table')*/)
		{	
				if($this->checkSecureForm())
					$this->onSubmit();
		}
		else $this->onLoad();

	}
	static function IsSubmit()
	{
	    return (Post::String('sslib_form_key')?true:false);
	}
	function onSubmit()
	{
		$this->checkSecureForm();
		
		if($this->id)
		{
			$checkUpdate = true;
			if(function_exists($this->table."_checkUpdateForm"))
				$checkUpdate = call_user_func($this->table."_checkUpdateForm");
			if($checkUpdate)	$this->doUpdate();
			else 				$this->onReload();			
		}
		else
		{
			$checkInsert = true;
			if(function_exists($this->table."_checkInsertForm"))
				$checkInsert = call_user_func($this->table."_checkInsertForm");
			if($checkInsert)	$this->doInsert();
			else				$this->onReload();
		}
	}
	function onReload()
	{
		$form = file_get_contents($this->form);
		print Form::MakeForm(Html::Exec($form, $this->form), $this->post);
	}
	function onLoad()
	{
		$form = file_get_contents($this->form);
				
		if($this->id)
		{
			if(function_exists($this->table.'_BeforeLoad'))	$query = call_user_func($this->table.'_BeforeLoad', $this->id);
			
			$data = Q(isset($query)?$query:"SELECT * FROM $this->table WHERE ".Sql::Quote($this->key, false)." = ".Sql::Quote($this->id));
			if($data->IsEmpty()){new Err(__T('field not found'));}

			print $this->MakeForm(Template::Compile(array('sslib_form_id'=>$this->id), $form), $data->All());
		}
		else
		{
			print $this->MakeForm(Template::Compile(array('sslib_form_id'=>''), $form), array());
		}
		
	}
	private function secureForm($form,$id)
	{
		$key = RandomKey(Form::$key_lenght).md5($this->table);
		$_SESSION[$key] = $id;
		$this->hidden_values['sslib_form_key'] = $key;
		$text = preg_replace("#<form([^>]*)>(.*)</form>#suU", '<form $1>'.($this->makeHiddenValues($this->hidden_values)).'$2</form>', $form);
		return $text;
	}
	private function checkSecureForm()
	{
		if(substr($this->post['sslib_form_key'], Form::$key_lenght) !== md5($this->table)) return false;
		$key = substr($this->post['sslib_form_key'], 0, Form::$key_lenght);
		$key = $this->post['sslib_form_key'];
		//if($this->table !== $this->post['sslib_form_table']) return false;
		if(!array_key_exists($key,$_SESSION))	return false;
		$this->id = $_SESSION[$key];
		unset($_SESSION[$key]);
		
		return true;
	}
	private function makeHiddenValues($arr)
	{
	    $ret = '';
	    foreach($this->hidden_values as $key => $val)
	        $ret .= '<input name="'.$key.'" id="'.$key.'" type="hidden" value="'.$val.'">';
 
	    return $ret;
	}
	function doInsert()
	{
		if(function_exists($this->table."_BeforeInsert"))	if(false === call_user_func($this->table."_BeforeInsert")) return;
		$this->post = Post::GetArray();
		
		unset($this->post['sslib_form_key']);
		unset($this->post['sslib_form_table']);
		
		$ret = Q("INSERT INTO $this->table ".Form::QueryValuesFromPost($this->post).';');
			
		if(function_exists($this->table."_AfterInsert")){call_user_func($this->table."_AfterInsert", Sslib::DB()->LastInseredOid()); }
		elseif(!Sslib::Debug())Page::Location(Request::Referer());
	}
	function doUpdate()
	{
	    if(function_exists($this->table."_BeforeUpdate"))	if(false === call_user_func($this->table."_BeforeUpdate", $this->id)) return;
	    $this->post = Post::GetArray();

		if(sizeof($this->post) < 1) new Err(__T('empty post'));
		unset($this->post['sslib_form_key']);
		unset($this->post['sslib_form_table']);
		
		
		Q("UPDATE $this->table SET ".Form::QuerySetFromPost($this->post)." WHERE ".Sql::Quote($this->key, false)." = ".Sql::Quote($this->id));
		if(function_exists($this->table."_AfterUpdate"))	call_user_func($this->table."_AfterUpdate", $this->id);
		elseif(!Sslib::Debug())Page::Location(Request::Referer());
	}
		
	static function QuerySetFromPost($post)
	{
		if(isset($post['submit'])){unset($post['submit']);}
		
		foreach($post as $key => $val)
		{
			if(is_array($val))     new Err(__T('wrong datatype')." $key");
		}
		return Sql::SetQuery(Form::safeText($post));
	}
	
	static function QueryValuesFromPost($post)
	{
		if(isset($post['submit'])){unset($post['submit']);}
		foreach($post as $key => $val)
		{
			if(is_array($val))    die(__T('wrong datatype')." $key");
		}
		return Sql::ValuesQuery(Form::safeText($post));
	}
	
	function MakeForm($form, $arr)
	{
		
		$this->formid = RandomKey(Form::$key_lenght,36);
		
		$form = preg_replace('#<form(.*?)>(.*?)</form>#isu', "<form id=\"$this->formid\" $1>$2</form>",$form);
		if(preg_match('#<form.*?action\s*?=\s*?".*?".*?>#isu', $form) < 1)
			$form = preg_replace('#<form(.*?)>(.*?)</form>#isu', "<form action=\"\" $1>$2</form>", $form);
		if(preg_match('#<form.*?method\s*?=\s*?".*?".*?>#isu', $form) < 1)
			$form = preg_replace('#<form(.*?)>(.*?)</form>#isu', "<form method=\"post\" $1>$2</form>", $form);
		if(preg_match('#<form.*?enctype\s*?=\s*?".*?".*?>#isu', $form) < 1)
			$form = preg_replace('#<form(.*?)>(.*?)</form>#isu', "<form enctype=\"multipart/form-data\" $1>$2</form>", $form);
		$form = str_ireplace('{sslib_form_submit}', __T('sslib_form_submit'), $form);
		$form = $this->secureForm($form, $this->id);
		if(sizeof($arr) > 1)
		return "$form<script type=\"text/javascript\">//<![CDATA[<!--
		sslib_fullform(".Form::MakeJavascriptArray($arr).",'$this->formid');//-->]]></script>\n";
		return $form;
	}
	
	static function MakeJavascriptArray($arr)
	{
		
		if(!$arr) return;
		$retArrKeys = 'new Array("';	
		$retArrVals = 'new Array("';
		
		
		foreach($arr as $key => $val)
		{
			//if(preg_match('#\d+#', $key)>0) continue;
			$val = trim($val);
			$val = str_replace('"', '\"', $val);
			$val = str_replace('\\\"', '\"', $val);
			$val = str_replace("\r", '\r', $val);
			$val = str_replace("\n", '\n', $val);
			$retArrKeys .= $key.'","';
			$retArrVals .= $val.'","';
		}
		return substr($retArrKeys, 0, -2)."),".substr($retArrVals, 0, -2).')';
	}
	public function FormID(){return $this->formid;}
	public function FieldID(){return $this->getFieldId();}
	
	private function getFieldId()
	{
		if($this->fieldid)
			return $this->fieldid;
		else if(!Request::Int($this->key))
			return null;
		return Request::String($this->key);
	}
	private static function safeText($text)
	{
	    if(is_array($text))
	    {
	        foreach($text as $key => $val)
	        {
	            $text[$key] = Text::Safe($val);   
	        }
	        return $text;
	    }
	    else return Text::Safe($val);	    
	}
}
?>